%locations
%define parse.error verbose

%{
#include <stdarg.h>	//引入头文件
#include "lex.yy.c"
Node* root = NULL;
Node** package(int childNum, Node* child1, ...);
void yyerror(const char* msg);
int synError = 0;
%}

/* declared tokens 关键字定义 */
/*终结符 词法单元 尖括号定义其类型*/
%token INT FLOAT ID SEMI COMMA ASSIGNOP RELOP 
%token PLUS MINUS STAR DIV AND OR DOT NOT TYPE LP RP LB RB LC RC STRUCT RETURN IF ELSE WHILE
%token MISSING_RIGHT_COMMENT

//非终结符 语法单元值的类型说明
%type Program ExtDefList ExtDef ExtDecList // High-level Definitions(高级定义)
%type Specifier StructSpecifier OptTag Tag // Specifiers(类型定义)
%type VarDec FunDec VarList ParamDec // Declarators(变量、函数声明)
%type CompSt StmtList Stmt // Statements(作用域(块))
%type DefList Def Dec DecList // Local Definitions(局部变量定义)
%type Exp Args // Expressions(表达式)

//priority 左结合，右结合，优先级设定与结合性
%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NOT
%left LP RP LB RB DOT

%nonassoc LOWER_THAN_ELSE //优先级比ELSE低
%nonassoc ELSE


%%
/* High-level Definitions */
Program : ExtDefList { $$ = createNode("Program", ENUM_SYN_NOT_NULL, @$.first_line, 
1, package(1, $1));
root = $$; }
;
ExtDefList : ExtDef ExtDefList { $$ = createNode("ExtDefList", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }  //多个ExtDef
| { $$ = createNode("ExtDefList", ENUM_SYN_NULL, @$.first_line, 0, NULL);}  //空的
;
ExtDef : Specifier ExtDecList SEMI { $$ = createNode("ExtDef", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //Specifier表示类型，ExtDecList表示零个或多个对一个变量的定义VarDec
| Specifier SEMI { $$ = createNode("ExtDef", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }  //int ;
| Specifier FunDec CompSt { $$ = createNode("ExtDef", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //Specifier是返回类型，FunDec是函数头（函数名+参数列表），CompSt表示函数体
| Specifier error SEMI { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少变量名
| error SEMI { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少类型
| Specifier error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少函数头
;
ExtDecList : VarDec { $$ = createNode("ExtDecList", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //VarDec表示一个变量的定义
| VarDec COMMA ExtDecList { $$ = createNode("ExtDecList", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //多个VarDec e.g.:i,j,k
;


/* Specifiers 类型定义*/
Specifier : TYPE { $$ = createNode("Specifier", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //int or float
| StructSpecifier { $$ = createNode("Specifier", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //结构体类型
;
StructSpecifier : STRUCT OptTag LC DefList RC { $$ = createNode("StructSpecifier", ENUM_SYN_NOT_NULL, @$.first_line, 5, package(5, $1, $2, $3, $4, $5)); }  //结构体定义
| STRUCT Tag { $$ = createNode("StructSpecifier", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); } //结构体名称
| STRUCT error LC DefList RC { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少结构体名称
| STRUCT OptTag LC error RC { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少结构体定义
| STRUCT OptTag LC error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少右大括号
| STRUCT error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少左大括号
;
OptTag : ID { $$ = createNode("OptTag", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //结构体名称
| { $$ = createNode("OptTag", ENUM_SYN_NULL, @$.first_line, 0, NULL); } //无结构体名称
;
Tag : ID { $$ = createNode("Tag", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //结构体名称
;


/* Declarators 变量、函数声明*/
VarDec : ID { $$ = createNode("VarDec", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //变量名
| VarDec LB INT RB { $$ = createNode("VarDec", ENUM_SYN_NOT_NULL, @$.first_line, 4, package(4, $1, $2, $3, $4)); }  //数组定义 e.g.:a[10]
| VarDec LB error RB { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少数组大小
| VarDec LB error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少右中括号
| error RB { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerror("Invalid expression."); yyerrok; }  //错误处理：缺少左中括号
;
FunDec : ID LP VarList RP { $$ = createNode("FunDec", ENUM_SYN_NOT_NULL, @$.first_line, 4, package(4, $1, $2, $3, $4)); } //函数头定义  e.g.:int main(int a, int b)
| ID LP RP { $$ = createNode("FunDec", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //函数头定义（无参数）  e.g.:int main()
| ID LP error RP { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少形参列表
| ID LP error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少右括号
| error RP { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerror("Invalid expression."); yyerrok; }  //错误处理：缺少左括号
;
VarList : ParamDec COMMA VarList { $$ = createNode("VarList", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //多形参列表  e.g.:int a, int b
| ParamDec { $$ = createNode("VarList", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //一个形参的定义  e.g.:int a
;
ParamDec : Specifier VarDec { $$ = createNode("ParamDec", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); } //一个形参的定义
;


/* Statements 作用域(块)*/
CompSt : LC DefList StmtList RC { $$ = createNode("CompSt", ENUM_SYN_NOT_NULL, @$.first_line, 4, package(4, $1, $2, $3, $4)); } //语块{...}包含局部定义语句和其他语句
| error RC { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少左大括号
| error RB { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少左中括号
;
StmtList : Stmt StmtList { $$ = createNode("StmtList", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }  //各行语句
| { $$ = createNode("StmtList", ENUM_SYN_NOT_NULL, @$.first_line, 0, NULL); } //空语句
;
Stmt : Exp SEMI { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); } //语句定义
| CompSt { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); }  //语块
| RETURN Exp SEMI { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //返回语句
| IF LP Exp RP Stmt %prec LOWER_THAN_ELSE { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 5, package(5, $1, $2, $3, $4, $5)); } //if语句  e.g.:if(a>0) b=1;
| IF LP Exp RP Stmt ELSE Stmt { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 7, package(7, $1, $2, $3, $4, $5, $6, $7)); } //if-else语句 e.g.:if(a>0) b=1; else b=0;
| WHILE LP Exp RP Stmt { $$ = createNode("Stmt", ENUM_SYN_NOT_NULL, @$.first_line, 5, package(5, $1, $2, $3, $4, $5)); }  //while语句
| error SEMI { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少分号
| IF LP error RP Stmt %prec LOWER_THAN_ELSE { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少表达式  e.g.:if()
| IF LP Exp RP error ELSE Stmt { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少表达式语句  e.g.:if(a>0) else b=0;
| IF LP error RP ELSE Stmt { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少表达式
| error LP Exp RP Stmt { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少if
| MISSING_RIGHT_COMMENT { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerror("Missing Right Comment."); yyerrok; }  //错误处理：缺少右注释
;


/* Local Definitions 局部变量定义*/
DefList : Def DefList { $$ = createNode("DefList", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }
| { $$ = createNode("Stmt", ENUM_SYN_NULL, @$.first_line, 0, NULL); } //空定义
;
Def : Specifier DecList SEMI { $$ = createNode("Def", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } // int a,b,c ;
;
DecList : Dec { $$ = createNode("DecList", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); }  //a,b,c
| Dec COMMA DecList { $$ = createNode("DecList", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //多个Dec
| Dec error DecList { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少逗号  e.g.:int a b;
;
Dec : VarDec { $$ = createNode("Dec", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //a,b[INT]
| VarDec ASSIGNOP Exp { $$ = createNode("Dec", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  // a=10
| error ASSIGNOP Exp { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少变量名
;


/* Expressions */
Exp : Exp ASSIGNOP Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //赋值表达式
| Exp AND Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //逻辑与表达式
| Exp OR Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //逻辑或表达式
| Exp RELOP Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //关系表达式
| Exp PLUS Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //加法表达式
| Exp MINUS Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //减法表达式
| Exp STAR Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //乘法表达式
| Exp DIV Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //除法表达式
| LP Exp RP { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); }  //括号表达式
| MINUS Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }  //负数表达式
| NOT Exp { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 2, package(2, $1, $2)); }  //逻辑非表达式
| ID LP Args RP { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 4, package(4, $1, $2, $3, $4)); }  //函数调用表达式
| ID LP RP { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //函数调用表达式
| Exp LB Exp RB { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 4, package(4, $1, $2, $3, $4)); }  //数组访问
| Exp DOT ID { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //结构体访问
| ID { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //标识符
| INT { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); }  //整数
| FLOAT { $$ = createNode("Exp", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); }  //浮点数
| Exp ASSIGNOP error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少表达式语句  e.g.:a=
| Exp AND error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp OR error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp RELOP error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp PLUS error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp MINUS error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp STAR error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| Exp DIV error { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }
| ID LP error RP { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; }  //错误处理：缺少实参列表  e.g.:fun()
| Exp LB error RB { $$ = createNode("Error", ENUM_SYN_NULL, @$.first_line, 0, NULL); yyerrok; } //错误处理：缺少表达式  e.g.:a[]
;
Args : Exp COMMA Args { $$ = createNode("Args", ENUM_SYN_NOT_NULL, @$.first_line, 3, package(3, $1, $2, $3)); } //实参列表
| Exp { $$ = createNode("Args", ENUM_SYN_NOT_NULL, @$.first_line, 1, package(1, $1)); } //一个实参
;
%%
//错误处理	Exp : Exp error LB Exp RB


Node** package(int childNum, Node* child1, ...) { //封装函数，用于返回多个子节点
    va_list ap;
    va_start(ap, child1); //初始化ap，使其指向第一个可变参数
    Node** res = (Node**)malloc(sizeof(Node*) * childNum);
    res[0] = child1;  //第一个参数
    for (int i = 1; i < childNum; i++)
    {
        res[i] = va_arg(ap, Node*); //获取下一个参数
    }
    return res;
}

void yyerror(const char* msg) {
    synError++;
    printf("Error type B at Line %d: %s\n", yylineno, msg);
}